package org.hertsig.deckbox;

import java.util.Iterator;
import java.util.List;

import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import lombok.Value;

import org.hertsig.deckbox.DeckFolder.DeckInfo;

import com.google.common.collect.Iterables;
import com.google.common.collect.TreeTraverser;

@Getter @AllArgsConstructor
public class DeckFolder implements Iterable<DeckInfo> {
	private final String name;
	private final List<DeckFolder> subfolders;
	private final List<DeckInfo> decks;
	
	/**
	 * @return all decks in this folder and its subfolders.
	 * Folders are traversed in breadth first order
	 * 
	 * @see TreeTraverser#breadthFirstTraversal(Object)
	 */
	public Iterable<DeckInfo> breadthFirstTraversal() {
		return Iterables.concat(tree().breadthFirstTraversal(this));
	}
	
	/**
	 * @return all decks in this folder and its subfolders.
	 * Folders are traversed in preorder
	 * 
	 * @see TreeTraverser#preOrderTraversal(Object)
	 */
	public Iterable<DeckInfo> preOrderTraversal() {
		return Iterables.concat(tree().preOrderTraversal(this));
	}
	
	/**
	 * @return all decks in this folder and its subfolders.
	 * Folders are traversed in post order
	 * 
	 * @see TreeTraverser#postOrderTraversal(Object)
	 */
	public Iterable<DeckInfo> postOrderTraversal() {
		return Iterables.concat(tree().postOrderTraversal(this));
	}
	
	private TreeTraverser<DeckFolder> tree() {
		return new TreeTraverser<DeckFolder>() {
			@Override
			public List<DeckFolder> children(DeckFolder element) {
				return element.getSubfolders();
			}
		};
	}
	
	@Override
	public Iterator<DeckInfo> iterator() {
		return decks.iterator();
	}
	
	@Override
	public String toString() {
		return toString(new StringBuilder(), "").toString();
	}
	
	private StringBuilder toString(StringBuilder sb, String indent) {
		sb.append(indent).append(name).append('\n');
		for (DeckFolder folder : subfolders) {
			folder.toString(sb, indent + "  ");
		}
		if (!decks.isEmpty()) {
			sb.append(indent + "  ").append(decks.size()).append(" decks\n");
		}
		return sb;
	}
	
	@ToString(of="name") @EqualsAndHashCode(of="deckId")
	public static @Value class DeckInfo {
		private final String deckId;
		private final String name;
	}
}
